Previous: Format Conversion Round-Trip, Up: Format Conversion [Contents][Index]
In contrast to the round-trip specification described in the
previous subsection (see
Format Conversion Round-Trip), you can use the variables
after-insert-file-functions and
write-region-annotate-functions to separately
control the respective reading and writing conversions.
Conversion starts with one representation and produces another representation. When there is only one conversion to do, there is no conflict about what to start with. However, when there are multiple conversions involved, conflict may arise when two conversions need to start with the same data.
This situation is best understood in the context of converting
text properties during write-region. For example,
the character at position 42 in a buffer is
‘X’ with a text property
foo. If the conversion for foo is done
by inserting into the buffer, say,
‘FOO:’, then that changes the character
at position 42 from ‘X’ to
‘F’. The next conversion will start with
the wrong data straight away.
To avoid conflict, cooperative conversions do not modify the
buffer, but instead specify annotations, a list of
elements of the form (position .
string), sorted in order of increasing
position.
If there is more than one conversion,
write-region merges their annotations destructively
into one sorted list. Later, when the text from the buffer is
actually written to the file, it intermixes the specified
annotations at the corresponding positions. All this takes place
without modifying the buffer.
In contrast, when reading, the annotations intermixed with the
text are handled immediately. insert-file-contents
sets point to the beginning of some text to be converted, then
calls the conversion functions with the length of that text.
These functions should always return with point at the beginning
of the inserted text. This approach makes sense for reading
because annotations removed by the first converter can’t be
mistakenly processed by a later converter. Each conversion
function should scan for the annotations it recognizes, remove
the annotation, modify the buffer text (to set a text property,
for example), and return the updated length of the text, as it
stands after those changes. The value returned by one function
becomes the argument to the next function.
A list of functions for write-region to call.
Each function in the list is called with two arguments: the
start and end of the region to be written. These functions
should not alter the contents of the buffer. Instead, they
should return annotations.
As a special case, a function may return with a different
buffer current. Emacs takes this to mean that the current
buffer contains altered text to be output. It therefore
changes the start and end arguments of
the write-region call, giving them the values of
point-min and point-max in the new
buffer, respectively. It also discards all previous
annotations, because they should have been dealt with by this
function.
The value of this variable, if non-nil,
should be a function. This function is called, with no
arguments, after write-region has completed.
If any function in
write-region-annotate-functions returns with a
different buffer current, Emacs calls
write-region-post-annotation-function more than
once. Emacs calls it with the last buffer that was current,
and again with the buffer before that, and so on back to the
original buffer.
Thus, a function in
write-region-annotate-functions can create a
buffer, give this variable the local value of
kill-buffer in that buffer, set up the buffer
with altered text, and make the buffer current. The buffer
will be killed after write-region is done.
Each function in this list is called by
insert-file-contents with one argument, the
number of characters inserted, and with point at the
beginning of the inserted text. Each function should leave
point unchanged, and return the new character count
describing the inserted text as modified by the function.
We invite users to write Lisp programs to store and retrieve text properties in files, using these hooks, and thus to experiment with various data formats and find good ones. Eventually we hope users will produce good, general extensions we can install in Emacs.
We suggest not trying to handle arbitrary Lisp objects as text property names or values—because a program that general is probably difficult to write, and slow. Instead, choose a set of possible data types that are reasonably flexible, and not too hard to encode.
Previous: Format Conversion Round-Trip, Up: Format Conversion [Contents][Index]